package engine.resource;

import engine.entities.Mob.MobSpriteSet;
import engine.game.gfx.ColoredSprite;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import engine.game.gfx.SpriteSheet;
import engine.game.level.Level;
import engine.game.level.LevelMap;
import engine.game.level.tiles.Tile;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import util.Logger;

/**
 * A static class for storing a games resources
 *
 * @author Nathan Templon
 *
 */
public class Resources {

    private static final Logger logger = Logger.getDefaultLogger();

    // State Variables
    private static final Map<String, SpriteSheet> sheets = new HashMap<>();
    private static final Map<String, Tile> tiles = new HashMap<>();
    private static final Map<String, LevelMap> levelMaps = new HashMap<>();
    private static final Map<String, Level> levels = new HashMap<>();
    private static final Map<String, MobSpriteSet> spriteSets = new HashMap<>();
    private static final Map<String, ColoredSprite> sprites = new HashMap<>();

    private static final Collection<String> gfxConfigs = new ArrayList<>();

    private static String resIniFilePath;

    // Static Access Methods
    /**
     * Accesses a SpriteSheet object stored under the provided name.
     *
     * @param s The name of the SpriteSheet to be accessed.
     *
     * @return Returns the SpriteSheet of that name if it exists, null if it
     *         does not.
     */
    public static SpriteSheet getSpriteSheet(String s) {
        if (sheets.containsKey(s)) {
            return sheets.get(s);
        }
        return null;
    }

    /**
     * Accesses a Tile object stored under the provided name.
     *
     * @param s The name of the Tile to be accessed.
     *
     * @return Returns the Tile of that name if it exists, null if it does not.
     */
    public static Tile getTile(String s) {
        if (tiles.containsKey(s)) {
            return tiles.get(s);
        }
        return null;
    }

    /**
     * Accesses a LevelMap object stored under the provided name.
     *
     * @param s The name of the LevelMap to be accessed.
     *
     * @return Returns the LevelMap of that name if it exists, null if it does
     *         not.
     */
    public static LevelMap getLevelMap(String s) {
        if (levelMaps.containsKey(s)) {
            return levelMaps.get(s);
        }
        return null;
    }

    public static Level getLevel(String s) {
        if (levels.containsKey(s)) {
            return levels.get(s);
        }
        return null;
    }

    public static MobSpriteSet getSpriteSet(String s) {
        if (spriteSets.containsKey(s)) {
            return spriteSets.get(s);
        }
        return null;
    }
    
    public static ColoredSprite getSprite(String s) {
        if (sprites.containsKey(s)) {
            return sprites.get(s);
        }
        return null;
    }
    
    public static String getResIniFilePath() {
        return resIniFilePath;
    }

    public static Collection<String> getLevelNames() {
        return levels.keySet();
    }

    public static Collection<String> getTileNames() {
        return tiles.keySet();
    }

    public static Collection<String> getGfxConfigs() {
        return gfxConfigs;
    }

    // Static Posting Methods
    /**
     * Adds a SpriteSheet object to the database
     *
     * @param s     The name
     * @param sheet of the SpriteSheet
     */
    public static void addSpriteSheet(String s, SpriteSheet sheet) {
        sheets.put(s, sheet);
    }

    /**
     * Adds a Tile object to the database
     *
     * @param s    The name of the Tile
     * @param tile The tile to be added
     */
    public static void addTile(String s, Tile tile) {
        tiles.put(s, tile);
    }

    /**
     * Adds a LevelMap object to the database
     *
     * @param s   The name of the LevelMap
     * @param map The LevelMap to be added
     */
    public static void addLevelMap(String s, LevelMap map) {
        levelMaps.put(s, map);
    }

    public static void addLevel(String s, Level level) {
        levels.put(s, level);
    }

    public static void addSpriteSet(String name, MobSpriteSet set) {
        spriteSets.put(name, set);
    }
    
    public static void addSprite(String name, ColoredSprite sprite) {
        sprites.put(name, sprite);
    }
    
    public static void removeLevel(String s) {
        if (levels.containsKey(s)) {
            levels.remove(s);
        }
    }
    
    public static void addGfxConfig(String filePath) {
        gfxConfigs.add(filePath);
    }

    public static void setResIniFilePath(String path) {
        resIniFilePath = path;
    }

    public static void saveConfig() {
        File cfg = new File(resIniFilePath);
        try {
            try (FileWriter fw = new FileWriter(cfg);
                    PrintWriter pw = new PrintWriter(fw)) {

                pw.println("[Graphics]");
                for (String gfxName : gfxConfigs) {
                    pw.println(gfxName);
                }

                pw.println("[Level]");
                for (String lvlName : levels.keySet()) {
                    pw.println(getRelativeFilePath(levels.get(lvlName).getFilePath()));
                }

            }
        }
        catch (IOException ex) {
            logger.log(ex);
        }
    }

    private static String getRelativeFilePath(String path) {
        String folderPath = ResourceInputFile.getFolderFrom(resIniFilePath);
        int indexOfFolder = resIniFilePath.indexOf(folderPath);
        return path.substring(indexOfFolder + folderPath.length());
    }

}
